<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
  <style>
      #canvas {
          background: #f1f1f1;
      }
  </style>
</head>
<body>
<canvas id="canvas" width="300" height="300"></canvas>
<script>
    window.onload = () => {
        const canvas = document.getElementById('canvas')
        const ctx = canvas.getContext('2d')
        // 绘制矩形
        // save 和 restore 方法是用来保存和恢复 canvas 状态的，都没有参数。Canvas 的状态就是当前画面应用的所有样式和变形的一个快照。
        // Canvas状态存储在栈中，每当save()方法被调用后，当前的状态就被推送到栈中保存。一个绘画状态包括：strokeStyle, fillStyle, globalAlpha ...等等
        // 你可以调用任意多次 save方法。每一次调用 restore 方法，上一个保存的状态就从栈中弹出，所有设定都恢复。
        const drawSaveAndRestore = () => {
            ctx.fillRect(0,0,150,150);   // 使用默认设置绘制一个矩形
            ctx.save();                  // 保存默认状态 保存了当前的fillStyle的默认值

            ctx.fillStyle = '#09F'       // 在原有配置基础上对颜色做改变
            ctx.fillRect(15,15,120,120); // 使用新的设置绘制一个矩形
            ctx.save();                  // 保存当前状态  保存了当前的fillStyle的值

            ctx.fillStyle = '#FFF'       // 再次改变颜色配置
            ctx.globalAlpha = 0.5;
            ctx.fillRect(30,30,90,90);   // 使用新的配置绘制一个矩形
            ctx.save();  // 保存当前状态  保存了当前的fillStyle、globalAlpha的值

            ctx.restore();               // 重新加载上一次之前的颜色状态
            ctx.fillRect(45,45,60,60);   // 使用上一次的配置绘制一个矩形

            ctx.restore();               // 加载上上一次的颜色配置
            ctx.fillRect(60,60,30,30);   // 使用加载的配置绘制一个矩形

            ctx.restore();   // 加载上上上一次的颜色配置，也就是默认的颜色配置
            ctx.fillRect(75,75,15,15);   // 使用加载的配置绘制一个矩形
        }
        // drawSaveAndRestore()


        // translate 方法接受两个参数。x 是左右偏移量，y 是上下偏移量，
        // draw 方法中调用 fillRect() 方法 9 次，用了 2 层循环。每一次循环，先保存初始的状态，然后移动 canvas ，画图案，然后恢复到原始状态。
        function drawTranslate(){
            for (let i = 0; i < 3; i++) {
                for (let j = 0; j < 3; j++) {
                    ctx.save()
                    ctx.fillStyle = 'rgb(' + (51 * i) + ', ' + (255 - 51 * i) + ', 255)';
                    ctx.translate(j*50,i*50)

                    // 如果不使用 translate 方法，那么所有矩形都将被绘制在相同的位置（0,0）。
                    ctx.fillRect(0,0,25,25)
                    ctx.restore()
                }

            }
        }
        // drawTranslate()

        function drawRotate() {
            var ctx = document.getElementById('canvas').getContext('2d');
            // 移动原点
            ctx.translate(75,75);

            for (var i=1;i<3;i++){ // Loop through rings (from inside to out)
                ctx.save();
                ctx.fillStyle = 'rgb('+(51*i)+','+(255-51*i)+',255)';

                for (var j=0;j<i*6;j++){ // draw individual dots
                    // rotate(angle) 这个方法只接受一个参数：旋转的角度(angle)，它是顺时针方向的，以弧度为单位的值。
                    ctx.rotate(Math.PI*2/(i*6));
                    ctx.beginPath();
                    ctx.arc(0,i*12.5,5,0,Math.PI*2,true);
                    ctx.fill();
                }

                ctx.restore();
            }
        }
        // drawRotate()

        // scale(x, y)   scale  方法可以缩放画布的水平和垂直的单位。
        // 两个参数都是实数，可以为负数，x 为水平缩放因子，y 为垂直缩放因子，如果比1小，会缩小图形， 如果比1大会放大图形。默认值为1， 为实际大小。
        function drawScale() {
            var ctx = document.getElementById('canvas').getContext('2d');

            // draw a simple rectangle, but scale it.
            // ctx.save();
            // ctx.scale(4, 2);
            // ctx.fillRect(10, 10, 10, 10);
            // ctx.restore();

            // mirror horizontally
            // 画布初始情况下， 是以左上角坐标为原点的第一象限。如果参数为负实数， 相当于以x 或 y轴作为对称轴镜像反转
            // 以y轴作为对称轴镜像反转， 就可得到著名的笛卡尔坐标系，左下角为原点。
            ctx.scale(1, -1);
            ctx.font = '48px serif';
            ctx.fillText('MDN', 135, -120);
        }
        drawScale()
    }

</script>
</body>
</html>
